package com.zhufeng.gateway.db.route;

import com.alibaba.fastjson.JSONObject;
import com.zhufeng.user.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.handler.AsyncPredicate;
import org.springframework.cloud.gateway.handler.predicate.ReadBodyRoutePredicateFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.function.Predicate;

/**
 * @ClassName: ZhufengUserReadBodyRoutePredicateFactory
 * @Description 自定义User报文体解析类
 * @author 月夜烛峰
 * @date 2022/9/18 12:16
 */
@Slf4j
@Component
public class ZhufengUserReadBodyRoutePredicateFactory extends ReadBodyRoutePredicateFactory {

    private static final String ZF_USER_ATTRIBUTE = "read_body_predicate_user_attribute";

    private static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";

    private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies
            .withDefaults().messageReaders();

    public ZhufengUserReadBodyRoutePredicateFactory() {
        super();
    }

    @Override
    public AsyncPredicate<ServerWebExchange> applyAsync(ReadBodyRoutePredicateFactory.Config config) {

        return exchange -> {
            Predicate<UserInfo> predicate = msgInfo -> {
                log.info("请求数据:" + msgInfo.getUserName());
                return true;
            };

            config.setPredicate(predicate);
            config.setInClass(UserInfo.class);

            log.info("打印属性formdata:{}",exchange.getFormData().toString());
            log.info("打印属性queryparam:{}",exchange.getRequest().getQueryParams());

            Class<UserInfo> inClass = config.getInClass();

            Object cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);

            if (cachedBody != null) {
                try {
                    boolean test = config.getPredicate().test(cachedBody);
                    exchange.getAttributes().put(ZF_USER_ATTRIBUTE, test);
                    return Mono.just(test);
                } catch (ClassCastException e) {
                    if (log.isDebugEnabled()) {
                        log.debug("Predicate test failed because class in predicate "
                                + "does not match the cached body object", e);
                    }
                }
                return Mono.just(false);
            } else {
                return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> ServerRequest.create(exchange.mutate().request(serverHttpRequest).build(), messageReaders).bodyToMono(inClass).doOnNext((objectValue) -> {
                    exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue);
                }).map((objectValue) -> {
                    UserInfo userInfo = (UserInfo)objectValue;
                    log.info(userInfo.getUserId()+":"+userInfo.getUserName());
                    return config.getPredicate().test(objectValue);
                }));
            }
        };
    }
}
